﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Cms.Application.WebFramework.Presenters;
using Cms.Domain;
using Cms.Domain.Authentication;
using Cms.Utilities;
using Cms.Web.Framework.Infrastructure.Wrappers;
using Content = Cms.Web.Framework.Controls.Content;

namespace Cms.Web.Framework.Infrastructure
{
    public class RequestDetails
    {
        private string _applicationPath;
        private RequestDetailsPresenter _presenter;
        private IList<string> _folders;
        private  string _pageFilename;
        private  string _queryString;
        private  string _requestedUrl;
        private  int _versionID;
        private DetailTemplate _detailTemplate;
        private Locale _locale;
        private MasterTemplate _masterTemplate;
        private Page _page;
        private Site _site;
        private ICmsHttpRequest _request;
        private ICmsIdentity _identity;

        public RequestDetails(ICmsHttpRequest request, ICmsIdentity identity)
        {
            Initialize(request, identity, new RequestDetailsPresenter());
        }

        // Unit test constructor
        public RequestDetails(ICmsHttpRequest request, ICmsIdentity identity, RequestDetailsPresenter presenter)
        {
            Initialize(request, identity, presenter);
        }

        private void Initialize(ICmsHttpRequest request, ICmsIdentity identity, RequestDetailsPresenter presenter)
        {
            _request = request;
            _identity = identity;
            _presenter = presenter;
            ContentPlaceHolders = new List<Content>();
            _applicationPath = request.ApplicationPath;
            if (_applicationPath.EndsWith("/"))
            {
                _applicationPath = _applicationPath.TrimEnd("/".ToCharArray());
            }
            _folders = new List<string>();
            string path = FoldersAndPage;
            int slashPosition = path.LastIndexOf("/");
            if (slashPosition >= 0)
            {
                _pageFilename = path.Remove(0, slashPosition + 1);
                foreach (string f in path.Remove(slashPosition).Split("/".ToCharArray()))
                    _folders.Add(f);
            }
            else
            {
                _pageFilename = path;
            }
            FirstFolderIsLocaleCode = false;
            if (_pageFilename == string.Empty)
            {
                _pageFilename = "Default.aspx";
            }
            _queryString = request.Url.Query;
            if (_queryString.StartsWith("?"))
            {
                _queryString = _queryString.Substring(1);
            }
            _requestedUrl = request.Url.AbsoluteUri;
            if (!string.IsNullOrEmpty(request.QueryString["VersionID"]))
            {
                _versionID = int.Parse(request.QueryString["VersionID"]);
            }
            else
            {
                _versionID = -1;
            }
        }

        public static RequestDetails Current
        {
            get { return (RequestDetails)HttpContext.Current.Items["RequestDetails"]; }
        }
        
        public RequestDetailsPresenter Presenter
        {
            get { return _presenter; }
        }
        
        public Page Page
        {
            get { return _page; }
            set { _page = value; }
        }
        
        public MasterTemplate MasterTemplate
        {
            get { return _masterTemplate; }
            set { _masterTemplate = value; }
        }
        
        public DetailTemplate DetailTemplate
        {
            get { return _detailTemplate; }
            set { _detailTemplate = value; }
        }

        public IList<Content> ContentPlaceHolders { get; private set; }
        
        public Site Site
        {
            get { return _site; }
            set { _site = value; }
        }
        
        public Locale Locale
        {
            get { return _locale; }
            set { _locale = value; }
        }

        public bool FirstFolderIsLocaleCode { get; private set; }

        public string SiteRootUrl
        {
            get
            {
                string url = _request.Url.Host;
                if (_request.Url.Port != 80)
                    url += ":" + _request.Url.Port;
                url += _applicationPath;
                return url;
            }
        }
        
        public string Protocol
        {
            get { return _request.Url.Scheme + Uri.SchemeDelimiter; }
        }
        
        public string FoldersAndPage
        {
            get { return _request.Url.AbsolutePath.Remove(0, _applicationPath.Length + 1); }
        }

        public string PageFilename
        {
            get { return _pageFilename; }
        }

        public string QueryString
        {
            get { return _queryString; }
        }
        
        public string RequestedUrl
        {
            get { return _requestedUrl; }
        }

        public bool AllowContentEditing
        {
            get { return _presenter.IsSitePreview(FoldersAndPage) && _request.AllowContentEditing; }
        }

        public ContentTranslationVersion ContentTranslationVersion
        {
            get { return _presenter.GetContentTranslationVersion(_versionID); }
        }
        
        public MediaFile MediaFile { get; private set; }

        public bool AdministratorMustBeLoggedOut
        {
            get
            {
                // Always log out administrators that have the ForceLogout flag set
                if (_presenter.AdministratorHasForcedLogout(AdministratorID))
                    return true;

                // Check if CurrentSite is set
                if (_presenter.AdministratorHasNoCurrentSite(AdministratorID))
                {
                    // No current site. Check if the admin has permission to create a new site, if not: log out
                    return !_presenter.AdministratorCanConfigureFirstSite(AdministratorID);
                }

                // Admin has a current site, proceed
                return false;
            }
        }

        public int AdministratorID
        {
            get
            {
                try
                {
                    if (_identity.Name != string.Empty)
                    {
                        AuthenticatedUser user = Conversion.ToAuthenticatedUser(_identity.Name);
                        return user.AdministratorID;
                    }
                }
                catch (Exception ex)
                {
                    Logging.LogError("AdministratorID could not be retrieved", ex);
                }
                return -1;
            }
        }

        public int UserID
        {
            get
            {
                try
                {
                    if (_identity.Name != string.Empty)
                    {
                        AuthenticatedUser user = Conversion.ToAuthenticatedUser(_identity.Name);
                        return user.UserID;
                    }
                }
                catch (Exception ex)
                {
                    Logging.LogError("UserID could not be retrieved", ex);
                }
                return -1;
            }
        }

        public Administrator Administrator
        {
            get { return Presenter.GetAdministrator(AdministratorID); }
        }

        public User User
        {
            get { return Presenter.GetUser(UserID); }
        }

        public bool IsSystemPageRequest()
        {
            if (_presenter.IsSystemPageRequest(FoldersAndPage))
            {
                if (_presenter.IsSitePreview(FoldersAndPage))
                {
                    if (_request.QueryString["LocaleID"] != null && _request.QueryString["LocaleID"] != string.Empty)
                    {
                        _locale = _presenter.GetLocale(int.Parse(_request.QueryString["LocaleID"]));
                        _site = _locale.Site;
                    }
                    if (_request.QueryString["MasterTemplateID"] != null && _request.QueryString["MasterTemplateID"] != string.Empty)
                    {
                        _masterTemplate = _presenter.GetMasterTemplate(int.Parse(_request.QueryString["MasterTemplateID"]));
                    }
                    if (_request.QueryString["DetailTemplateID"] != null && _request.QueryString["DetailTemplateID"] != null)
                    {
                        _detailTemplate = _presenter.GetDetailTemplate(int.Parse(_request.QueryString["DetailTemplateID"]));
                    }
                    if (_request.QueryString["PageID"] != null && _request.QueryString["PageID"] != null)
                    {
                        _page = _presenter.GetPage(int.Parse(_request.QueryString["PageID"]));
                    }
                }
                return true;
            }
            return false;
        }

        public bool SingleSignOnAuthorizationRequired()
        {
            return _presenter.SingleSignOnAuthorizationRequired(FoldersAndPage);
        }

        public void ResolveSiteAndLocale()
        {
            _site = _presenter.GetSite(SiteRootUrl);
            if (_site == null)
            {
                // No site found, try the locales alias domains.
                _locale = _presenter.GetLocaleByAliasDomain(SiteRootUrl);
                if (_locale == null)
                    return;
                _site = _locale.Site;
            }
            if (_site == null)
                return;
            if (_locale == null && _folders.Count() > 0)
            {
                // Check if the top folder is a locale code
                _locale = _site.GetLocaleByUrlCode(_folders[0]);
            }
            if (_locale == null)
                _locale = _site.DefaultLocale;
            else
                FirstFolderIsLocaleCode = true;
        }

        public bool IsMediaFile()
        {
            int i = FirstFolderIsLocaleCode ? 1 : 0;
            if (_folders.Count == i || _folders[i].ToLower() != _site.RootMediaFolder.ToLower())
                return false;
            MediaFile = _presenter.GetMediaFile(_site, _folders, _pageFilename);
            return MediaFile != null;
        }

        public bool IsRssFeed()
        {
            int i = FirstFolderIsLocaleCode ? 1 : 0;
            if (_folders.Count == i || _folders[i].ToLower() != "rss")
                return false;
            return _presenter.GetRssFeed(_site, _pageFilename) != null;
        }

        public bool GetPage()
        {
            _page = _presenter.GetPage(_site, _folders, FirstFolderIsLocaleCode, _pageFilename, AdministratorID);
            if (_page == null)
                return false;
            _masterTemplate = _page.MasterTemplate;
            _detailTemplate = _page.DetailTemplate;
            return true;
        }
        
        public void RenderContent()
        {
            if (_presenter.IsSitePreview(FoldersAndPage) ||
                (_versionID > 0 && ContentTranslationVersion != null && AdministratorID > 0))
            {
                foreach (Content c in ContentPlaceHolders)
                {
                    c.RenderContent(this);
                    if (AllowContentEditing)
                        c.RenderEditAreaLinks(this);
                }
            }
            else
            {
                foreach (Content c in ContentPlaceHolders)
                    c.RenderPublishedContent(this);
            }
        }
        
        public string GetQueryStringValue(string key)
        {
            foreach (string pair in
                _queryString.Split("&".ToCharArray()).Where(
                    pair => pair.Length > 0 && pair.Substring(0, pair.IndexOf("=")).ToLower() == key.ToLower()))
            {
                return HttpUtility.UrlDecode(pair.Substring(pair.IndexOf("=") + 1));
            }
            return string.Empty;
        }
    }
}